<template>
    <div class="bpmn-modeler-container">
        <div class="content" :class="{ 'with-error': error, 'with-diagram': hasDiagram }"
            @dragover.prevent="handleDragOver" @drop.prevent="handleDrop">
            <div v-if="!hasDiagram && !error" class="message intro">
                <div class="note">
                    将BPMN流程图从桌面拖放进来，或者<a href="#" @click.prevent="createNewDiagram">新建一个流程图</a>以开始
                </div>
            </div>

            <div v-if="error" class="message error">
                <div class="note">
                    <p>Ooops, we could not display the BPMN 2.0 diagram.</p>
                    <div class="details">
                        <span>cause of the problem</span>
                        <pre>{{ error }}</pre>
                    </div>
                </div>
            </div>

            <div ref="canvas" class="canvas"></div>
        </div>

        <ul class="buttons">
            <li>
                <a href="#" :class="{ active: hasDiagram }" @click.prevent="downloadDiagram"
                    title="download BPMN diagram">
                    BPMN 流程图
                </a>
            </li>
            <li>
                <a href="#" :class="{ active: hasDiagram }" @click.prevent="downloadSVG" title="download as SVG image">
                    SVG 图像
                </a>
            </li>
        </ul>
    </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { useDebounceFn } from '@vueuse/core'  // VueUse 7.0+ 标准用法
import BpmnModeler from 'bpmn-js/lib/Modeler'
import 'bpmn-js/dist/assets/diagram-js.css'
import 'bpmn-js/dist/assets/bpmn-js.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'
import defaultDiagram from '../resources/newDiagram.bpmn?raw'
import customTranslateModule from '../custom-translate/customTranslate.js'; // 自定义翻译模块

const canvas = ref(null)
const modeler = ref(null)
const error = ref(null)
const hasDiagram = ref(false)

// 初始化建模器
onMounted(() => {
    console.log('Canvas element:', canvas.value) // 应输出DOM元素
    console.log('Modeler instance:', modeler.value) // 应输出BpmnModeler实例
    if (!canvas.value) return

    modeler.value = new BpmnModeler({
        container: canvas.value,
        additionalModules: [
            {
                translate: ['value', customTranslateModule] // 注入自定义翻译模块
            }
        ]
    })
    /*  */
    // 设置导出防抖函数
    const exportArtifacts = useDebounceFn(async () => {
        try {
            const { svg } = await modeler.value.saveSVG()
            setEncoded('diagram.svg', svg)
        } catch (err) {
            console.error('Error saving SVG:', err)
        }

        try {
            const { xml } = await modeler.value.saveXML({ format: true })
            setEncoded('diagram.bpmn', xml)
        } catch (err) {
            console.error('Error saving BPMN:', err)
        }
    }, 500)

    modeler.value.on('commandStack.changed', exportArtifacts)

    // 检查文件API支持
    if (!window.FileList || !window.FileReader) {
        alert('Looks like you use an older browser that does not support drag and drop. Try using Chrome, Firefox or the Internet Explorer > 10.')
    }
})

onBeforeUnmount(() => {
    if (modeler.value) {
        modeler.value.destroy()
    }
})

// 创建新图表
const createNewDiagram = async () => {
    await openDiagram(defaultDiagram)
}

// 打开图表
const openDiagram = async (xml) => {
    try {
        await modeler.value.importXML(xml)
        error.value = null
        hasDiagram.value = true
    } catch (err) {
        error.value = err.message
        hasDiagram.value = false
        console.error(err)
    }
}

// 处理文件拖放
const handleDrop = (e) => {
    const files = e.dataTransfer.files
    if (!files.length) return

    const file = files[0]
    const reader = new FileReader()

    reader.onload = (e) => {
        openDiagram(e.target.result)
    }

    reader.readAsText(file)
}

const handleDragOver = (e) => {
    e.dataTransfer.dropEffect = 'copy'
}

// 下载功能
const setEncoded = (filename, data) => {
    if (!data) return

    const encodedData = encodeURIComponent(data)
    const link = document.createElement('a')
    link.href = `data:application/bpmn20-xml;charset=UTF-8,${encodedData}`
    link.download = filename
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
}

const downloadDiagram = async () => {
    if (!hasDiagram.value) return

    try {
        const { xml } = await modeler.value.saveXML({ format: true })
        setEncoded('diagram.bpmn', xml)
    } catch (err) {
        console.error('Error saving BPMN:', err)
    }
}

const downloadSVG = async () => {
    if (!hasDiagram.value) return

    try {
        const { svg } = await modeler.value.saveSVG()
        setEncoded('diagram.svg', svg)
    } catch (err) {
        console.error('Error saving SVG:', err)
    }
}
</script>

<style scoped>
.bpmn-modeler-container {
    height: 100vh;
    display: flex;
    flex-direction: column;
}

.content {
    flex: 1;
    position: relative;
    overflow: hidden;
    background-color: #f5f5f5;
    border: 1px solid #ccc;
}

.canvas {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
}

.message {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    text-align: center;
    z-index: 10;
}

.with-diagram .message {
    display: none;
}

.buttons {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    gap: 10px;
    padding: 10px;
    background-color: #f5f5f5;
    border-top: 1px solid #ccc;
}

.buttons a {
    padding: 5px 10px;
    background-color: #eee;
    border: 1px solid #ccc;
    border-radius: 3px;
    text-decoration: none;
    color: #333;
}

.buttons a.active {
    background-color: #e0e0e0;
    cursor: pointer;
}

.buttons a:not(.active) {
    color: #999;
    cursor: not-allowed;
}
</style>